import json

from decimal import Decimal

import time
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin

"""
订单结算页面的展示需求
"""


class PlaceOrderView(LoginRequiredMixin, View):
    def get(self, request):
        #
        #     1.这个界面必须是登陆用户
        #     2.获取用户信息,'
        user = request.user
        #     3.根据用户信息,获取地址信息
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except Exception as e:
            return http.HttpResponseNotFound('未找到数据')
        # 4.连接redis,获取redis中的 hash和set数据
        redis_conn = get_redis_connection('carts')
        #         hash:
        sku_id＿count = redis_conn.hgetall('carts_%s' % user.id)
        #         set:
        ids = redis_conn.smembers('selected_%s' % user.id)
        #     5.将bytes数据类型进行转换,转换的同时我们重新组织选中的商品数据
        #         只有选中的 {sku_id:count}
        selected_carts = {}
        for id in ids:
            selected_carts[int(id)] = int(sku_id＿count[id])
        # 6.获取商品的id,根据商品id查询商品信息 [sku,sku]
        ids = selected_carts.keys()
        # __in 获取
        skus = SKU.objects.filter(pk__in=ids)
        #     7.对商品列表进行遍历
        total_count = 0  # 总数量
        from decimal import Decimal  # 货币类型
        total_amount = Decimal('0')  # 重金额
        for sku in skus:
            #     8.遍历的过程中 对sku添加数量和对应商品的总金额
            sku.count = selected_carts[sku.id]
            sku.amount = sku.count * sku.price
            #         也去计算当前订单的总数量和总金额
            total_count += sku.count
            total_amount += sku.amount
        # 添加运费信息
        freight = Decimal('10.00')
        # total_amount += freight
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight
        }

        return render(request, 'place_order.html', context=context)


# 生成订单信息需要涉及到订单基本信息和订单商品信息, 因为
#     订单基本信息订单商品信息
#     是1对n, 所以先生成1(订单基本信息)
#     的数据, 再生成订单商品
#
class OrderCommitView(LoginRequiredJSONMixin, View):
    def post(self, request, ):
        #     1.生成订单基本信息
        #         1.1必须是登陆用户才可以访问.获取用户信息
        user = request.user
        #         1.2 获取提交的地址信息
        data = json.loads(request.body.decode())
        address_id = data.get('address_id')
        # 查询地址是否正确
        try:
            address = Address.objects.get(pk=address_id)
        except Address.DoesNotExist:
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数错误'})
        # 1.3 获取提交的支付方式
        pay_method = int(data.get('pay_method'))
        # 获取支付方式


        if not pay_method in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数错误'})

        # return  http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数错误'})
        #         1.4手动生成一个订单id年月日时分秒 + 9位用户id
        # 年Y Yｅａｒ　月　m month　　日 d day　时 H Hour　分　M　Month 　秒 S Second
        from django.utils import timezone
        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + '%09d' % user.id
        #         1.5运费, 总金额和总数量(初始化为0)
        freight = Decimal('10.00')
        total_amount = Decimal('10.00')
        total_count = 0
        #         1.6订单状态(由支付方式决定)
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            # 货到付款
            status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:  # 支付宝
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        # 2.生成订单商品信息，模型里边有的的数据
        with transaction.atomic():
            # 创建事务回滚的点
            save_point = transaction.savepoint()

            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                pay_method=pay_method,
                status=status

            )
            #         2.1连接redis.获取redis中的数据,选中商品的信息{sku_id:count}
            redis_conn = get_redis_connection('carts')
            # hash
            id_count = redis_conn.hgetall('carts_%s' % user.id)
            # set
            selected_ids = redis_conn.smembers('selected_%s' % user.id)
            selected_carts = {}
            for id in selected_ids:

                selected_carts[int(id)] = int(id_count[id])
                # 2.2获取选中商品的id[1, 2, 3]
            ids = selected_carts.keys()
                #         2.3对id进行遍历
            for id in ids:
                while True:
                # while True:
                #         2.4查询商品
                    sku = SKU.objects.get(pk=id)
                #         2.5库存量的判断
                # 销量
                    count = selected_carts[sku.id]
                    if sku.stock < count:
                        # 出现问题进行回滚
                        transaction.savepoint_rollback(save_point)
                        # 说明库从不足
                        return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库从不足'})
                        #         2.6修改商品的库存和销量
                        # 设置　并发，时间
                    time.sleep(1)
                    # sku.stock -= count
                    # sku.sales += count
                    # sku.save()
                    # 先获取之前的库存
                    old_stock = sku.stock
                    # 新的库存,售买量
                    new_stock = sku.stock - count  # count销量
                    new_sales = sku.sales + count
                    # 更新数据前再次查询库存
                    rect = SKU.objects.filter(id=sku.id, stock=old_stock).update(
                        stock=new_stock,
                        sales=new_sales
                    )
                    # 下单失败进行事务回滚
                    if rect == 0:
                        continue
                    #     transaction.savepoint_rollback(save_point)
                    #     # return http.JsonResponse({'code':RETCODE.STOCKERR,'errmsg':'下单失败'})
                    #     raise Exception('下单失败')
                    # else:
                    #     print('下单成功')
                    # 2.7累加总数量和总金额
                    order.total_count += count
                    order.total_amount += (sku.price * count)
                    #         2.8保存订单商品信息
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=count,
                        price=sku.price
                    )
                    #下单成功
                    break
        #         2.9保存订单的总数量和总金额
            order.save()
            # 3.提交
            transaction.savepoint_commit(save_point)
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'order_id': order_id})
        # 3.提交
        # 4.删除redis中选中的商品信息


class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,  # 订单ｉｄ
            'payment_amount': payment_amount,  # 金额
            'pay_method': pay_method  # 支付方式
        }
        return render(request, 'order_success.html', context)
